﻿
''' <summary>
''' Compares the properties of two generic objects.
''' </summary>
''' <typeparam name="T">The type of the compared objects</typeparam>
''' <remarks></remarks>
Public Class PropertyComparer(Of T)
    Implements IComparer(Of T)
    Private mSortDescriptions As New List(Of PropertySortDescription(Of T))
    ''' <summary>
    ''' The sort descriptions for comparing in ordination to this list. If a property is equal with both objects, the next property description in list will be used for comparing until one object differs to the other.
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public ReadOnly Property SortDescriptions() As List(Of PropertySortDescription(Of T))
        Get
            Return mSortDescriptions
        End Get
    End Property
    ''' <summary>
    ''' Compares both objects.
    ''' </summary>
    ''' <param name="x">First Object</param>
    ''' <param name="y">Second Object</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function Compare(ByVal x As T, ByVal y As T) As Integer Implements IComparer(Of T).Compare
        For Each desc In mSortDescriptions
            Dim xValue As Object = desc.Descriptor.GetValue(x)
            Dim yValue As Object = desc.Descriptor.GetValue(y)
            Dim res As Integer = desc.Direction * desc.Comparer.Compare(xValue, yValue)
            If res <> 0 Then Return res
        Next
        Return 0
    End Function
End Class

''' <summary>
''' Provides properties for storing reflection information of a generic object.
''' </summary>
''' <typeparam name="T">The type of the object</typeparam>
''' <remarks></remarks>
Public Class PropertySortDescription(Of T)
    Private mDescriptor As PropertyDescriptor
    Private mDirection As ListSortDirection = ListSortDirection.Ascending
    Private mComparer As System.Collections.IComparer
    Friend ReadOnly Property Comparer() As System.Collections.IComparer
        Get
            Return mComparer
        End Get
    End Property
    Public ReadOnly Property Descriptor() As PropertyDescriptor
        Get
            Return mDescriptor
        End Get
    End Property
    Public Property Direction() As ListSortDirection
        Get
            Return mDirection
        End Get
        Set(ByVal value As ListSortDirection)
            mDirection = value
        End Set
    End Property
    Public Sub New(ByVal pd As PropertyDescriptor, ByVal dir As ListSortDirection)
        Me.New(pd)
        mDirection = dir
    End Sub
    Public Sub New(ByVal pd As PropertyDescriptor)
        If pd Is Nothing Then : Throw New ArgumentNullException("pd", "Property descriptor is not allowed to be null/Nothing.")
        Else
            mDescriptor = pd
            mComparer = DirectCast(GetType(Comparer(Of T)).MakeGenericType(mDescriptor.PropertyType).InvokeMember("Default", Reflection.BindingFlags.GetProperty Or Reflection.BindingFlags.[Public] Or Reflection.BindingFlags.[Static], Nothing, Nothing, Nothing), System.Collections.IComparer)
        End If
    End Sub
End Class
